// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//

#pragma once

#include <turbo/base/nullability.h>
#include <turbo/memory/arena.h>

namespace cantor {
    template<class T>
    class ArenaAllocator {
    public:
        using value_type = T;

    public:
        ArenaAllocator(turbo::Nonnull<turbo::Arena *> arena) : arena_(arena) {
        }

        template<class U>
        ArenaAllocator(const ArenaAllocator<U> &other) : arena_(other.arena_) {
        }

        T *allocate(size_t n) {
            return static_cast<T *>(arena_->allocate(sizeof(T) * n));
        }

        void deallocate(T *p, size_t n) noexcept {
        }

        turbo::Arena *arena() const { return arena_; }

        template<class U>
        bool operator==(const ArenaAllocator<U> &other) const {
            return arena_ == other.arena_;
        }

        template<class U>
        bool operator!=(const ArenaAllocator<U> &other) const {
            return !(*this == other);
        }

    private:
        turbo::Arena *arena_;
    };

    template<class T, typename... Args>
    T *alloc_type(turbo::Arena &arena, Args &&... args) {
        auto p = static_cast<T *>(arena.allocate(sizeof(T)));
        new(p) T(std::forward<Args>(args)...);
        return p;
    }
} // namespace cantor
